using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace OpenWaves.Collections
{
    public static class EnumerableExtensions
    {
        private static readonly Random seedRandomizer = new Random();
        [ThreadStatic]
        private static Random threadRandom;

        private static Random ThreadRandom
        {
            get
            {
                if (threadRandom == null)
                {
                    lock (seedRandomizer)
                    {
                        threadRandom = new Random(seedRandomizer.Next());
                    }
                }
                return threadRandom;
            }
        }


        public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
        {
            return enumerable.Any() == false;
        }

        public static IEnumerable<IEnumerable<T>> GroupBy<T>(this IEnumerable<T> enumerable, int groupSize)
        {
            Contract.Requires<ArgumentNullException>(enumerable != null);
            Contract.Requires<ArgumentOutOfRangeException>(groupSize > 0);

            var currentGroup = new List<T>();
            foreach (var item in enumerable)
            {
                if (currentGroup.Count < groupSize)
                {
                    currentGroup.Add(item);
                }
                else
                {
                    yield return currentGroup;
                    currentGroup = new List<T>();
                    currentGroup.Add(item);
                }
            }

            yield return currentGroup;
        }

        public static IEnumerable<T> TakeRandom<T>(this IEnumerable<T> source, int count)
        {
            return source.Shuffle().Take(count);
        }

        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
        {
            var array = source.ToArray();
            var n = array.Length;
            while (n > 1)
            {
                var k = ThreadRandom.Next(n);
                n--;
                var temp = array[n];
                array[n] = array[k];
                array[k] = temp;
            }

            return array;
        }

    }
}